package freedom.needle.server.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import freedom.needle.enums.TaskCommand;
import freedom.needle.server.TaskServer;
import freedom.needle.sleep.SleepWindowEvent;
import freedom.needle.sleep.SleepWindowEventListener;
import freedom.needle.task.impl.AbstractCycleTask;

public abstract class AbstractTaskServer implements TaskServer, SleepWindowEventListener {
	
	protected final Logger logger = LoggerFactory.getLogger(getClazz());
	protected AbstractCycleTask[] tasks;
	protected ThreadPoolTaskExecutor threadPoolTaskExecutor;
	private volatile TaskCommand command = TaskCommand.INIT;
	
	public AbstractTaskServer(AbstractCycleTask[] tasks, ThreadPoolTaskExecutor threadPoolTaskExecutor) {
		this.tasks = tasks;
		this.threadPoolTaskExecutor = threadPoolTaskExecutor;
		init();
	}

	protected abstract Class<?> getClazz();

	private void init() {
		for (int i = 0; i < tasks.length; i++) {
			for (int j = 0; j < tasks[i].getWorkers(); j++) {
				Thread t = threadPoolTaskExecutor.newThread(tasks[i]);
				threadPoolTaskExecutor.execute(t);
			}
		}
	};

	@Override
	public void start() {
		synchronized (command) {
			if(command == TaskCommand.INIT || command == TaskCommand.PAUSE) {
				logger.info("starting...");
				this.publishCommand(TaskCommand.RUN);
				this.command = TaskCommand.RUN;
				logger.info("started.");
			}
			else if(command == TaskCommand.RUN) {
				logger.info("already started!");
			}
			else {
				//STOP
				logger.info("already stopped! try to restart.");
			}
		}
	}

	private void publishCommand(TaskCommand command) {
		for (int i = 0; i < tasks.length; i++) {
			tasks[i].setCommand(command);
		}
		
		threadPoolTaskExecutor.getThreadGroup().interrupt();
		
		try {
			Thread.sleep(20);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void pause() {
		synchronized (command) {
			if(command == TaskCommand.INIT || command == TaskCommand.RUN) {
				logger.info("pausing...");
				this.publishCommand(TaskCommand.PAUSE);
				this.command = TaskCommand.PAUSE;
				logger.info("paused.");
			}
			else if(command == TaskCommand.PAUSE) {
				logger.info("already paused!");
			}
			else {
				//STOP
				logger.info("already stopped. cannot pause!");
			}
		}
	}

	@Override
	public void stop() {
		synchronized (command) {
			if(command == TaskCommand.INIT || command == TaskCommand.RUN || command == TaskCommand.PAUSE) {
				logger.info("stopping...");
				this.publishCommand(TaskCommand.STOP);
				while(isStop()) {
					this.command = TaskCommand.STOP;
					logger.info("stopped.");
				}
			}
			else {
				//STOP
				logger.info("already stopped!");
			}
		}
	}

	private boolean isStop() {
		//TODO
		return false;
	}

	@Override
	public void restart() {
		synchronized (command) {
			if(command != TaskCommand.STOP) {
				stop();
			}
			init();
			start();
		}
	}
	
	/**
	 * @param tasks the tasks to set
	 */
	public void setTasks(AbstractCycleTask[] tasks) {
		this.tasks = tasks;
	}

	public void setThreadPoolTaskExecutor(
			ThreadPoolTaskExecutor threadPoolTaskExecutor) {
		this.threadPoolTaskExecutor = threadPoolTaskExecutor;
	}

	/**
	 * @return the command
	 */
	public TaskCommand getCommand() {
		return command;
	}

	@Override
	public void handleEvent(SleepWindowEvent event) {
		if(event.isOpen() && this.command == TaskCommand.RUN) {
			this.pause();
		}
		else if(!event.isOpen() && this.command != TaskCommand.RUN) {
			this.start();
		}
	}



}
